/**
 * @brief 计算一个进程cpu占用率的例子
 * note
 * 在一个64核机器上，理论上，每隔1s，总cpu jiffies计数应该增加6400，而包含9个死循环子线程的进程cpu jiffies应增加900。
 * 但实测发现打印如下：
 *  900 6361 905.518%
    900 6359 905.803%
    904 6359 909.829%
    900 6369 904.381%
    900 6361 905.518%
    900 6365 904.949%
    900 6360 905.66%
    904 6363 909.257%
    900 6376 903.388%
    900 6364 905.091%
    总cpu jiffies每次增加都少于6400，所以导致计算得到的进程cpu占用率约大于900%
*/

#include <cstdint>
#include <fstream>
#include <string>
#include <algorithm>
#include <numeric>
#include <thread>
#include <sstream>
#include <iostream>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <unistd.h>

void GetCpuTime(int64_t* totalTime, int64_t* useTime) {
    std::string strLine;
    {
        std::ifstream ifs("/proc/stat");
        std::getline(ifs, strLine, '\n');
    }

    std::istringstream istr(strLine);
    std::string cpuName;
    istr>> cpuName;
    int64_t item_time[10] = {0};
    for (int i = 0; i < 10; i++) {
        istr>> item_time[i];
    }

    *totalTime = std::accumulate(item_time, item_time + 10, 0);
    *useTime = std::accumulate(item_time, item_time + 3, 0);
}

int64_t GetProcessCpuTime(int pid)
{
    std::string strLine;
    {
        std::string fileName = std::string("/proc/") + std::to_string(pid) + "/stat";
        std::ifstream ifs(fileName);
        std::getline(ifs, strLine);
    }
    
    std::istringstream istr(strLine);
    std::string str_skip;
    for (int i = 0; i < 13; i++) {
        istr >> str_skip;
    }

    // man 5 proc
    int64_t utime, stime, cutime, cstime;
    istr>> utime >> stime >> cutime >> cstime;

    return utime + stime + cutime + cstime;
}

void s(void)
{
    while (1){}
}

int main(void)
{
    int64_t lastTotalTime = 0;
    int64_t lastUseTime = 0;
    int cpuCnt = get_nprocs();

    std::thread t[9];
    std::generate(t, t + 9, [](void){return std::thread(s);});
    int pid = getpid();

    GetCpuTime(&lastTotalTime, &lastUseTime);
    int64_t lastProcessTime = GetProcessCpuTime(pid);
    while (1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        int64_t totalTime = 0;
        int64_t useTime = 0;
        GetCpuTime(&totalTime, &useTime);
        int64_t processTime = GetProcessCpuTime(pid);

        double a = (processTime - lastProcessTime) * 100.0;
        double b = totalTime - lastTotalTime;
        std::cout<< (processTime - lastProcessTime) <<  " " << b << " ";
        std::cout << a * cpuCnt / b << "%\n";

        lastTotalTime = totalTime;
        lastProcessTime = processTime;
    }

}